package cn.zcltd.btg.set.sourcemanager;

import cn.zcltd.btg.set.ParamType;
import cn.zcltd.btg.set.core.Config;
import cn.zcltd.btg.set.core.Module;
import cn.zcltd.btg.set.core.Param;
import cn.zcltd.btg.set.exception.BtgSetRuntimerException;
import cn.zcltd.btg.sutil.EmptyUtil;
import cn.zcltd.btg.sutil.FileUtil;
import cn.zcltd.btg.sutil.filescanner.FileScanner;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 配置加载器：从json文件中获取配置
 */
public class JsonFileSourceManager extends SourceManager {

    private String folderPath; //文件存放路径
    private String fileEncoding; //文件编码

    public JsonFileSourceManager(String name, String folderPath) {
        super(name);
        this.folderPath = folderPath;
    }

    public JsonFileSourceManager(String name, String folderPath, String fileEncoding) {
        super(name);
        this.folderPath = folderPath;
        this.fileEncoding = fileEncoding;
    }

    public String getFolderPath() {
        return folderPath;
    }

    public void setFolderPath(String folderPath) {
        this.folderPath = folderPath;
    }

    public String getFileEncoding() {
        return fileEncoding;
    }

    public void setFileEncoding(String fileEncoding) {
        this.fileEncoding = fileEncoding;
    }

    @Override
    public void init(boolean devModel) {
        setDevMode(devModel);

        File fileFolder = new File(this.folderPath);
        FileUtil.mkDir(fileFolder);
        if (!fileFolder.isDirectory()) {
            throw new RuntimeException(this.folderPath + " not a directory");
        }

        List<Config> configs = loadAll();
        for (Config config : configs) {
            getCache().put(config.getId(), config);
        }

        log.debug("init success");
    }

    @Override
    public List<Config> loadAll() {
        List<Config> configs = new ArrayList<Config>();
        Map<String, Config> configMapLoaded = new HashMap<String, Config>();

        List<File> files = FileScanner.findFiles(this.folderPath, ".*\\.json");
        for (File file : files) {
            Config config = this.loadFromFile(file);
            if (configMapLoaded.get(config.getId()) != null) {
                throw new RuntimeException(config.getId() + " already exists");
            }
            configs.add(config);
            configMapLoaded.put(config.getId(), config);
        }

        return configs;
    }

    @Override
    public Config load(String configId) {
        String fileName = configId + ".json";

        List<File> files = FileScanner.findFiles(this.folderPath, ".*\\.json");
        for (File file : files) {
            if (fileName.equals(file.getName())) {
                return this.loadFromFile(file);
            }
        }

        return null;
    }

    @Override
    public void save(Config config) {
        if (null == config) {
            throw new BtgSetRuntimerException("config must not be null");
        }

        String filePath = this.folderPath + config.getId() + ".json";
        String configStr = config.toJson();
        FileUtil.write(filePath, configStr, FileUtil.ENCODING_UTF_8);

        getCache().put(config.getId(), config);
    }

    /**
     * 从文件中加载Config
     *
     * @param file 文件
     * @return 配置对象
     */
    private Config loadFromFile(File file) {
        String configStr = FileUtil.readToString(file, this.fileEncoding);
        return parse(configStr);
    }

    /**
     * 将json格式配置转化为配置对象
     *
     * @param jsonStr json格式字符串
     * @return 配置对象
     */
    public static Config parse(String jsonStr) {
        Config config;

        try {
            if (EmptyUtil.isEmpty(jsonStr)) {
                throw new BtgSetRuntimerException("content is empty");
            }

            /*
                读取配置转换为json
             */
            JSONObject configJson = JSONObject.parseObject(jsonStr);

            /*
                解析config属性
             */
            String id = configJson.getString("id");
            if (EmptyUtil.isEmpty(id)) {
                throw new BtgSetRuntimerException("id must not be empty ");
            }
            String name = configJson.getString("name");
            config = Config.createConfig(id, name);

            String desc = configJson.getString("desc");
            config.setDesc(desc);

            /*
                解析config>param
             */
            JSONArray paramJsonArray = configJson.getJSONArray("params");
            if (null != paramJsonArray && paramJsonArray.size() > 0) {
                for (int i = 0, l = paramJsonArray.size(); i < l; i++) {
                    JSONObject paramJson = paramJsonArray.getJSONObject(i);

                    String paramId = paramJson.getString("id");
                    if (EmptyUtil.isEmpty(paramId)) {
                        throw new BtgSetRuntimerException("id must not be empty:params[" + i + "]");
                    }
                    String paramName = paramJson.getString("name");
                    String paramDataType = paramJson.getString("type");
                    if (EmptyUtil.isEmpty(paramDataType)) {
                        throw new BtgSetRuntimerException("type must not be empty:params[" + i + "]");
                    }
                    String paramValue = paramJson.getString("value");

                    Param param = config.createParam(paramId, paramName, ParamType.valueOf(paramDataType), paramValue);

                    String paramDesc = paramJson.getString("desc");
                    param.setDesc(paramDesc);

                    String paramDatePattern = paramJson.getString("datePattern");
                    param.setDatePattern(paramDatePattern);

                    String paramRemark = paramJson.getString("remark");
                    param.setRemark(paramRemark);
                }
            }

            /*
                解析config>module
             */
            JSONArray moduleJsonArray = configJson.getJSONArray("modules");
            if (null != moduleJsonArray && moduleJsonArray.size() > 0) {
                for (int i = 0, l = moduleJsonArray.size(); i < l; i++) {
                    JSONObject moduleJson = moduleJsonArray.getJSONObject(i);

                    String moduleId = moduleJson.getString("id");
                    if (EmptyUtil.isEmpty(moduleId)) {
                        throw new BtgSetRuntimerException("id must not be empty:modules[" + i + "]");
                    }
                    String moduleName = moduleJson.getString("name");

                    Module module = config.createModule(moduleId, moduleName);

                    String moduleDesc = moduleJson.getString("desc");
                    module.setDesc(moduleDesc);

                    /*
                        解析config>mofule>param
                     */
                    JSONArray moduleParamJsonArray = moduleJson.getJSONArray("params");
                    if (null != moduleParamJsonArray && moduleParamJsonArray.size() > 0) {
                        for (int ii = 0, ll = moduleParamJsonArray.size(); ii < ll; ii++) {
                            JSONObject moduleParamJson = moduleParamJsonArray.getJSONObject(ii);

                            String paramId = moduleParamJson.getString("id");
                            if (EmptyUtil.isEmpty(paramId)) {
                                throw new BtgSetRuntimerException("id must not be empty:modules[" + i + "]>params[" + ii + "]");
                            }
                            String paramName = moduleParamJson.getString("name");
                            String paramDataType = moduleParamJson.getString("type");
                            if (EmptyUtil.isEmpty(paramDataType)) {
                                throw new BtgSetRuntimerException("type must not be empty:modules[" + i + "]>params[" + ii + "]");
                            }
                            String paramValue = moduleParamJson.getString("value");

                            Param moduleParam = module.createParam(paramId, paramName, ParamType.valueOf(paramDataType), paramValue);

                            String paramDesc = moduleParamJson.getString("desc");
                            moduleParam.setDesc(paramDesc);

                            String paramDatePattern = moduleParamJson.getString("datePattern");
                            moduleParam.setDatePattern(paramDatePattern);

                            String paramRemark = moduleParamJson.getString("remark");
                            moduleParam.setRemark(paramRemark);
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new BtgSetRuntimerException("load error:" + e.getMessage(), e);
        }

        return config;
    }
}